package com.gitee.mp.core.mapper;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ClassUtil;
import cn.hutool.core.util.ReflectUtil;
import cn.hutool.core.util.TypeUtil;
import com.gitee.mp.core.connector.MilvusConnector;
import com.gitee.mp.core.exception.InterceptException;
import com.gitee.mp.core.interceptor.InterceptorContext;
import com.gitee.mp.domain.definition.CollectionDefinition;
import com.gitee.mp.extend.MapperInterceptor;
import com.gitee.mp.extend.DefinitionParser;
import com.gitee.mp.infra.constants.MilvusPlusConstants;
import lombok.Getter;
import org.springframework.util.CollectionUtils;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.List;

/**
 * @author hongda.li
 */
@Getter
public final class MilvusMapperHandler implements InvocationHandler {

    private final Class<?> mapper;

    private final Class<?> entity;

    private final MilvusConnector connector;

    private final CollectionDefinition definition;

    private final List<MapperInterceptor> interceptors;

    /**
     * Milvus Mapper 接口的代理逻辑处理器
     *
     * @param mapper           Mapper 接口类型
     * @param connector        Mapper 接口对应的连接器
     * @param definitionParser 集合定义信息解析器
     * @param interceptors     Mapper 接口拦截器集合
     */
    public MilvusMapperHandler(Class<?> mapper,
                               MilvusConnector connector,
                               DefinitionParser definitionParser,
                               List<MapperInterceptor> interceptors) {
        this.mapper = mapper;
        this.connector = connector;
        this.interceptors = interceptors;
        this.entity = (Class<?>) TypeUtil.getTypeArgument(mapper);
        this.definition = definitionParser.parse(entity);
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        return switch (method.getName()) {
            case MilvusPlusConstants.MethodName.METHOD_TO_STRING -> this.toString();
            case MilvusPlusConstants.MethodName.METHOD_HASH_CODE -> this.hashCode();
            case MilvusPlusConstants.MethodName.METHOD_EQUALS -> this.equals(args[0]);
            default -> this.handle(proxy, method, args);
        };
    }

    private Object handle(Object proxy, Method method, Object[] args) throws Throwable {
        // 默认方法
        if (method.isDefault()) {
            return ReflectUtil.invokeRaw(proxy, method, args);
        }

        // 空插件
        if (CollectionUtils.isEmpty(this.interceptors)) {
            return ClassUtil.getDefaultValue(method.getReturnType());
        }

        InterceptorContext context = InterceptorContext.fromHandler(this);
        context.setMethod(method);
        context.setArguments(CollUtil.newArrayList(args));

        this.interceptors.stream()
                // 过滤出支持当前方法的拦截器
                .filter(interceptor -> interceptor.supported(method))
                // 依次调用插件
                .forEach(interceptor -> {
                    try {
                        interceptor.intercept(context);
                    } catch (Exception e) {
                        throw new InterceptException(e);
                    }
                });

        return context.getResult();
    }
}
